package com.thebeastshop.hotlink.spring;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.thebeastshop.hotlink.annotation.Hotlink;
import com.thebeastshop.hotlink.manager.HotlinkInterfaceKeyManager;
import com.thebeastshop.hotlink.proxy.HotlinkProxy;
import com.thebeastshop.hotlink.util.MethodUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


public class HotlinkScanner implements BeanPostProcessor, PriorityOrdered {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    @SuppressWarnings("rawtypes")
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class clazz = bean.getClass();
        List<Class> interfaceList = new ArrayList<>();

        if (clazz.isInterface()){
            interfaceList.add(clazz);
        }else{
            interfaceList.addAll(ListUtil.toList(clazz.getInterfaces()));
        }

        boolean needToProxy = false;
        for (Class interfaceClazz : interfaceList){
            Hotlink hotlinkAtClass = AnnotationUtil.getAnnotation(interfaceClazz, Hotlink.class);
            //如果接口上标注了@Hotlink，则接口下每一个方法都视为标注了@Hotlink
            //如果接口上没标注，则循环找接口上每一个方法是否标注了@Hotlink
            if (ObjectUtil.isNotNull(hotlinkAtClass)){
                for (Method method : ReflectUtil.getPublicMethods(clazz)){
                    String interfaceKey = MethodUtil.getInterfaceMethodStr(interfaceClazz, method);
                    log.info("[Hotlink] [{}]被扫描器扫描到，加入Hotlink元信息", interfaceKey);
                    HotlinkInterfaceKeyManager.addKey(interfaceKey);
                    needToProxy = true;
                }
            }else{
                for (Method method : ReflectUtil.getPublicMethods(interfaceClazz)){
                    Hotlink hotlinkAtMethod = AnnotationUtil.getAnnotation(method, Hotlink.class);
                    if (ObjectUtil.isNotNull(hotlinkAtMethod)){
                        String interfaceKey = MethodUtil.getInterfaceMethodStr(interfaceClazz, method);
                        log.info("[Hotlink] [{}]被扫描器扫描到，加入Hotlink元信息", interfaceKey);
                        HotlinkInterfaceKeyManager.addKey(interfaceKey);
                        needToProxy = true;
                    }
                }
            }
        }

        //说明这个类的接口中至少有一个方法被标注了@Hotlink
        if (needToProxy){
            HotlinkProxy hotlinkProxy = new HotlinkProxy(bean);
            bean = Proxy.newProxyInstance(hotlinkProxy.getClass().getClassLoader(), interfaceList.toArray(new Class[]{}), hotlinkProxy);
        }

        return bean;
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}
